package com.zz.common.protocol;


import com.zz.common.annotation.Protocol;
import com.zz.common.config.Config;
import com.zz.common.exception.TunnelException;
import com.zz.common.protocol.handle.DefaultProtocolHandle;
import com.zz.common.protocol.handle.ProtocolHandle;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 通信协议处理工厂
 *
 * @author zz
 */
@Slf4j
public class ProtocolFactory {

    /**
     * 通信协议缓存
     */
    private final static Map<String, Class<? extends TunnelProtocol>> protocolCache = new ConcurrentHashMap<>();

    /**
     * 协议处理器缓存
     */
    private final static Map<Class<? extends TunnelProtocol>, Class<? extends ProtocolHandle>>
            protocolHandleCache = new ConcurrentHashMap<>();

    /**
     * 协议处理器对象缓存
     */
    private static final Map<Class<? extends TunnelProtocol>, ProtocolHandle>
            protocolHandleMap = new ConcurrentHashMap<>();


    static {
        ServiceLoader<TunnelProtocol> protocols = ServiceLoader.load(TunnelProtocol.class);
        for (TunnelProtocol protocol : protocols) {
            Protocol annotation = protocol.getClass().getAnnotation(Protocol.class);
            if (Objects.isNull(annotation)) {
                log.error("{} 未配置通信协议", protocol.getClass().getName());
                throw new TunnelException("未配置通信协议");
            }
            protocolCache.put(annotation.value(), protocol.getClass());
            protocolHandleCache.put(protocol.getClass(), annotation.handle());
        }
    }


    public static Class<? extends TunnelProtocol> getProtocolByConfig(String protocolName) {
        return protocolCache.getOrDefault(protocolName, DefaultProtocol.class);
    }

    public static Class<? extends ProtocolHandle> getProtocolHandle(Class<? extends TunnelProtocol> protocolClass) {
        return protocolHandleCache.getOrDefault(protocolClass, DefaultProtocolHandle.class);
    }

    public static TunnelProtocol protocolNewInstance(Class<? extends TunnelProtocol> protocolClass) {
        try {
            return protocolClass.newInstance();
        } catch (Exception e) {
            log.error("通信协议配置异常");
            throw new TunnelException("通信协议配置异常");
        }
    }

    public static ProtocolHandle handleNewInstance(Class<? extends ProtocolHandle> handleClass) {
        try {
            return handleClass.newInstance();
        } catch (Exception e) {
            log.error("通信协议处理器配置异常");
            throw new TunnelException("通信协议处理器配置异常");
        }
    }

    public static ProtocolHandle getProtocolHandle() {
        try {
            Class<? extends TunnelProtocol> protocolClass = Config.getInstance().getProtocol();
            ProtocolHandle protocolHandle = protocolHandleMap.get(protocolClass);
            if (null == protocolHandle) {
                protocolHandle = handleNewInstance(getProtocolHandle(protocolClass));
                protocolHandleMap.put(protocolClass, protocolHandle);
            }
            return protocolHandle;
        } catch (Exception e) {
            log.error("通信协议配置异常");
            throw new TunnelException("通信协议配置异常");
        }

    }
}
